{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "first_steps_with_tensor_flow.ipynb",
      "version": "0.3.2",
      "views": {},
      "default_view": {},
      "provenance": [],
      "collapsed_sections": [
        "ajVM7rkoYXeL",
        "ci1ISxxrZ7v0",
        "copyright-notice"
      ]
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "copyright-notice",
        "colab_type": "text"
      },
      "source": [
        "#### Copyright 2017 Google LLC."
      ]
    },
    {
      "outputs": [],
      "cell_type": "code",
      "metadata": {
        "id": "copyright-notice2",
        "colab_type": "code",
        "cellView": "both",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ],
      "execution_count": 0
    },
    {
      "metadata": {
        "id": "4f3CKqFUqL2-",
        "colab_type": "text",
        "slideshow": {
          "slide_type": "slide"
        }
      },
      "cell_type": "markdown",
      "source": [
        " # Primeros pasos con TensorFlow"
      ]
    },
    {
      "metadata": {
        "id": "Bd2Zkk1LE2Zr",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " **Objetivos de aprendizaje:**\n",
        "  * aprender los conceptos fundamentales de TensorFlow\n",
        "  * usar la clase `LinearRegressor` en TensorFlow para predecir el precio mediano de la vivienda, en el nivel de detalle de las manzanas, basado en un atributo de entrada\n",
        "  * evaluar la exactitud de las predicciones de un modelo a trav\u00e9s del error de la ra\u00edz cuadrada de la media (RMSE)\n",
        "  * mejorar la exactitud de un modelo al ajustar sus hiperpar\u00e1metros"
      ]
    },
    {
      "metadata": {
        "id": "MxiIKhP4E2Zr",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " Los datos se basan en el censo que se realiz\u00f3 en 1990 en California."
      ]
    },
    {
      "metadata": {
        "id": "6TjLjL9IU80G",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " ## Preparaci\u00f3n\n",
        "En esta primera celda, cargaremos las bibliotecas necesarias."
      ]
    },
    {
      "metadata": {
        "id": "rVFf5asKE2Zt",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "from __future__ import print_function\n",
        "\n",
        "import math\n",
        "\n",
        "from IPython import display\n",
        "from matplotlib import cm\n",
        "from matplotlib import gridspec\n",
        "from matplotlib import pyplot as plt\n",
        "import numpy as np\n",
        "import pandas as pd\n",
        "from sklearn import metrics\n",
        "import tensorflow as tf\n",
        "from tensorflow.python.data import Dataset\n",
        "\n",
        "tf.logging.set_verbosity(tf.logging.ERROR)\n",
        "pd.options.display.max_rows = 10\n",
        "pd.options.display.float_format = '{:.1f}'.format"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "ipRyUHjhU80Q",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " A continuaci\u00f3n, cargaremos nuestro conjunto de datos."
      ]
    },
    {
      "metadata": {
        "id": "9ivCDWnwE2Zx",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "california_housing_dataframe = pd.read_csv(\"https://download.mlcc.google.com/mledu-datasets/california_housing_train.csv\", sep=\",\")"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "vVk_qlG6U80j",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " Dispondremos los datos de forma aleatoria para asegurarnos de no obtener efectos de orden compulsivo que podr\u00edan afectar el rendimiento del descenso de gradiente estoc\u00e1stico. Adem\u00e1s, ajustaremos `median_house_value` para que est\u00e9 en unidades de miles, de manera que se pueda aprender m\u00e1s f\u00e1cilmente con tasas de aprendizaje en un rango que usamos generalmente."
      ]
    },
    {
      "metadata": {
        "id": "r0eVyguIU80m",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "california_housing_dataframe = california_housing_dataframe.reindex(\n",
        "    np.random.permutation(california_housing_dataframe.index))\n",
        "california_housing_dataframe[\"median_house_value\"] /= 1000.0\n",
        "california_housing_dataframe"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "HzzlSs3PtTmt",
        "colab_type": "text",
        "slideshow": {
          "slide_type": "-"
        }
      },
      "cell_type": "markdown",
      "source": [
        " ## An\u00e1lisis de los datos\n",
        "\n",
        "Una buena idea es conocer un poco los datos antes de trabajar con ellos.\n",
        "\n",
        "Imprimiremos un breve resumen de algunas estad\u00edsticas \u00fatiles de cada columna: conteo de ejemplos, media, desviaci\u00f3n est\u00e1ndar, m\u00e1x., m\u00edn. y varios cuantiles."
      ]
    },
    {
      "metadata": {
        "id": "gzb10yoVrydW",
        "colab_type": "code",
        "slideshow": {
          "slide_type": "slide"
        },
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          },
          "test": {
            "output": "ignore",
            "timeout": 600
          }
        },
        "cellView": "both"
      },
      "source": [
        "california_housing_dataframe.describe()"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "Lr6wYl2bt2Ep",
        "colab_type": "text",
        "slideshow": {
          "slide_type": "-"
        }
      },
      "cell_type": "markdown",
      "source": [
        " ## Creaci\u00f3n del primer modelo\n",
        "\n",
        "En este ejercicio, intentaremos predecir `median_house_value`, que ser\u00e1 nuestra etiqueta (a veces tambi\u00e9n denominada objetivo). Usaremos `total_rooms` como nuestro atributo de entrada.\n",
        "\n",
        "**NOTA:** Nuestros datos est\u00e1n a nivel de manzana, de manera que este atributo representa el n\u00famero total de habitaciones en esa manzana.\n",
        "\n",
        "Para entrenar nuestro modelo, usaremos la interfaz de [LinearRegressor](https://www.tensorflow.org/api_docs/python/tf/estimator/LinearRegressor) que proporciona la API de [Estimator](https://www.tensorflow.org/get_started/estimator) de TensorFlow. Esta API se ocupa en gran medida del ajuste del modelo de bajo nivel y presenta m\u00e9todos convenientes para realizar el entrenamiento, la evaluaci\u00f3n y la inferencia del modelo."
      ]
    },
    {
      "metadata": {
        "id": "0cpcsieFhsNI",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " ### Paso\u00a01: Define atributos y configura columnas de atributos"
      ]
    },
    {
      "metadata": {
        "id": "EL8-9d4ZJNR7",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " Para importar nuestros datos de entrenamiento en TensorFlow, debemos especificar qu\u00e9 tipo de datos contiene cada atributo. Hay dos tipos de datos principales que usaremos en este ejercicio y en otros futuros:\n",
        "\n",
        "* **Datos categ\u00f3ricos**: Datos que son textuales. En este ejercicio, nuestro conjunto de datos de viviendas no contiene atributos categ\u00f3ricos, pero los ejemplos que podr\u00edas ver son el estilo de la casa o las palabras en un anuncio de bienes ra\u00edces.\n",
        "\n",
        "* **Datos num\u00e9ricos**: Datos que son un n\u00famero (entero o de punto flotante) y que quieres tratar como un n\u00famero. Como se analizar\u00e1 m\u00e1s adelante, a veces quieres tratar los datos num\u00e9ricos (p.\u00a0ej., un c\u00f3digo postal) como si fueran categ\u00f3ricos.\n",
        "\n",
        "En TensorFlow, indicamos el tipo de datos de un atributo a trav\u00e9s de un constructo denominado **columna de atributos**. Las columnas de atributos almacenan solo una descripci\u00f3n de los datos de los atributos; no contienen los datos de los atributos en s\u00ed.\n",
        "\n",
        "Para comenzar, usaremos solo un atributo de entrada num\u00e9rica, `total_rooms`. El siguiente c\u00f3digo extrae los datos de `total_rooms` de nuestro `california_housing_dataframe` y define la columna de atributos con `numeric_column`, que especifica que los datos son num\u00e9ricos:"
      ]
    },
    {
      "metadata": {
        "id": "rhEbFCZ86cDZ",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "# Define the input feature: total_rooms.\n",
        "my_feature = california_housing_dataframe[[\"total_rooms\"]]\n",
        "\n",
        "# Configure a numeric feature column for total_rooms.\n",
        "feature_columns = [tf.feature_column.numeric_column(\"total_rooms\")]"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "K_3S8teX7Rd2",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " **NOTA:** La forma de nuestros datos de `total_rooms` es una matriz de una dimensi\u00f3n (una lista del n\u00famero total de habitaciones por cada manzana). Esta es la forma predeterminada para `numeric_column`, de manera que no tenemos que pasarla como un argumento."
      ]
    },
    {
      "metadata": {
        "id": "UMl3qrU5MGV6",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " ### Paso\u00a02: Define el objetivo"
      ]
    },
    {
      "metadata": {
        "id": "cw4nrfcB7kyk",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " A continuaci\u00f3n, definiremos nuestro objetivo, que es `median_house_value`. Nuevamente, podemos extraerlo de nuestro `california_housing_dataframe`:"
      ]
    },
    {
      "metadata": {
        "id": "l1NvvNkH8Kbt",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "# Define the label.\n",
        "targets = california_housing_dataframe[\"median_house_value\"]"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "4M-rTFHL2UkA",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " ### Paso\u00a03: Configura el regresor lineal"
      ]
    },
    {
      "metadata": {
        "id": "fUfGQUNp7jdL",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " A continuaci\u00f3n, configuraremos un modelo de regresi\u00f3n lineal a trav\u00e9s de LinearRegressor. Entrenaremos este modelo mediante el `GradientDescentOptimizer`, que implementa el descenso de gradiente estoc\u00e1stico (SGD) de minilote. El argumento `learning_rate` controla el tama\u00f1o del paso de gradiente.\n",
        "\n",
        "**NOTA:** Para estar seguros, tambi\u00e9n aplicamos [recorte de gradientes](https://developers.google.com/machine-learning/glossary/#gradient_clipping) a nuestro optimizador a trav\u00e9s de `clip_gradients_by_norm`. El recorte de gradientes garantiza que la magnitud de los gradientes no se vuelva demasiado grande durante el entrenamiento, lo cual puede provocar que falle el descenso de gradientes. "
      ]
    },
    {
      "metadata": {
        "id": "ubhtW-NGU802",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "# Use gradient descent as the optimizer for training the model.\n",
        "my_optimizer=tf.train.GradientDescentOptimizer(learning_rate=0.0000001)\n",
        "my_optimizer = tf.contrib.estimator.clip_gradients_by_norm(my_optimizer, 5.0)\n",
        "\n",
        "# Configure the linear regression model with our feature columns and optimizer.\n",
        "# Set a learning rate of 0.0000001 for Gradient Descent.\n",
        "linear_regressor = tf.estimator.LinearRegressor(\n",
        "    feature_columns=feature_columns,\n",
        "    optimizer=my_optimizer\n",
        ")"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "-0IztwdK2f3F",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " ### Paso\u00a04: Define la funci\u00f3n de entrada"
      ]
    },
    {
      "metadata": {
        "id": "S5M5j6xSCHxx",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " Para importar nuestros datos de viviendas en California a nuestro `LinearRegressor`, tenemos que definir una funci\u00f3n de entrada, que instruye a TensorFlow c\u00f3mo realizar el procesamiento previo de los datos, adem\u00e1s de c\u00f3mo organizarlos por lotes, aleatorizarlos y repetirlos durante el entrenamiento del modelo.\n",
        "\n",
        "Primero, convertiremos nuestros datos de atributos de *pandas* a un diccionario de matrices de Numpy. A continuaci\u00f3n, podemos usar la [API del conjunto de datos](https://www.tensorflow.org/programmers_guide/datasets) de TensorFlow para construir un objeto de conjunto de datos a partir de nuestros datos y, luego, dividir nuestros datos en lotes de `batch_size` para que se repitan para el n\u00famero especificado de repeticiones (num_epochs). \n",
        "\n",
        "**NOTA:** Cuando el valor predeterminado de `num_epochs=None` se pasa como argumento a la función `repeat()`, los datos de entrada se repiten indefinidamente.\n",
        "\n",
        "A continuación, si `shuffle` está establecido en `True`, se aleatorizarán los datos de manera tal que se pasen al modelo al azar durante el entrenamiento. El argumento `buffer_size` de la función `shuffle` especifica el tamaño del conjunto de datos del que se tomará una muestra al azar.\n",
        "\n",
        "Finalmente, nuestra funci\u00f3n de entrada construye una variable de iteraci\u00f3n para el conjunto de datos y devuelve el siguiente lote de datos al regresor lineal."
      ]
    },
    {
      "metadata": {
        "id": "RKZ9zNcHJtwc",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "def my_input_fn(features, targets, batch_size=1, shuffle=True, num_epochs=None):\n",
        "    \"\"\"Trains a linear regression model of one feature.\n",
        "  \n",
        "    Args:\n",
        "      features: pandas DataFrame of features\n",
        "      targets: pandas DataFrame of targets\n",
        "      batch_size: Size of batches to be passed to the model\n",
        "      shuffle: True or False. Whether to shuffle the data.\n",
        "      num_epochs: Number of epochs for which data should be repeated. None = repeat indefinitely\n",
        "    Returns:\n",
        "      Tuple of (features, labels) for next data batch\n",
        "    \"\"\"\n",
        "  \n",
        "    # Convert pandas data into a dict of np arrays.\n",
        "    features = {key:np.array(value) for key,value in dict(features).items()}                                           \n",
        " \n",
        "    # Construct a dataset, and configure batching/repeating.\n",
        "    ds = Dataset.from_tensor_slices((features,targets)) # warning: 2GB limit\n",
        "    ds = ds.batch(batch_size).repeat(num_epochs)\n",
        "    \n",
        "    # Shuffle the data, if specified.\n",
        "    if shuffle:\n",
        "      ds = ds.shuffle(buffer_size=10000)\n",
        "    \n",
        "    # Return the next batch of data.\n",
        "    features, labels = ds.make_one_shot_iterator().get_next()\n",
        "    return features, labels"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "wwa6UeA1V5F_",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " **NOTA:** Seguiremos usando esta misma funci\u00f3n de entrada en ejercicios posteriores. Para obtener documentaci\u00f3n m\u00e1s detallada de las funciones de entrada y la API del `Dataset`, consulta la [Gu\u00eda para programadores de TensorFlow](https://www.tensorflow.org/programmers_guide/datasets)."
      ]
    },
    {
      "metadata": {
        "id": "4YS50CQb2ooO",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " ### Paso\u00a05: Entrena el modelo"
      ]
    },
    {
      "metadata": {
        "id": "yP92XkzhU803",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " Ahora podemos llamar a `train()` en nuestro `linear_regressor` para entrenar el modelo. Uniremos `my_input_fn` en una `lambda` para poder pasar `my_feature` y `target` como argumentos (para obtener m\u00e1s detalles, consulta este [instructivo sobre funciones de entrada de TensorFlow](https://www.tensorflow.org/get_started/input_fn#passing_input_fn_data_to_your_model)) y, para comenzar, entrenaremos el modelo para 100 pasos."
      ]
    },
    {
      "metadata": {
        "id": "5M-Kt6w8U803",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "_ = linear_regressor.train(\n",
        "    input_fn = lambda:my_input_fn(my_feature, targets),\n",
        "    steps=100\n",
        ")"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "7Nwxqxlx2sOv",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " ### Paso\u00a06: Eval\u00faa el modelo"
      ]
    },
    {
      "metadata": {
        "id": "KoDaF2dlJQG5",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " Realicemos predicciones sobre los datos de entrenamiento para ver qu\u00e9 tan bien los ajust\u00f3 nuestro modelo durante el entrenamiento.\n",
        "**NOTA:** El error de entrenamiento mide qu\u00e9 tan bien ajusta los datos de entrenamiento tu modelo, pero **_no_** mide qu\u00e9 tan bien el modelo **_realiza generalizaciones con respecto a los datos nuevos_**. En ejercicios posteriores, explorar\u00e1s c\u00f3mo dividir los datos para evaluar la capacidad del modelo para realizar generalizaciones.\n"
      ]
    },
    {
      "metadata": {
        "id": "pDIxp6vcU809",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "# Create an input function for predictions.\n",
        "# Note: Since we're making just one prediction for each example, we don't \n",
        "# need to repeat or shuffle the data here.\n",
        "prediction_input_fn =lambda: my_input_fn(my_feature, targets, num_epochs=1, shuffle=False)\n",
        "\n",
        "# Call predict() on the linear_regressor to make predictions.\n",
        "predictions = linear_regressor.predict(input_fn=prediction_input_fn)\n",
        "\n",
        "# Format predictions as a NumPy array, so we can calculate error metrics.\n",
        "predictions = np.array([item['predictions'][0] for item in predictions])\n",
        "\n",
        "# Print Mean Squared Error and Root Mean Squared Error.\n",
        "mean_squared_error = metrics.mean_squared_error(predictions, targets)\n",
        "root_mean_squared_error = math.sqrt(mean_squared_error)\n",
        "print(\"Mean Squared Error (on training data): %0.3f\" % mean_squared_error)\n",
        "print(\"Root Mean Squared Error (on training data): %0.3f\" % root_mean_squared_error)"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "AKWstXXPzOVz",
        "colab_type": "text",
        "slideshow": {
          "slide_type": "slide"
        }
      },
      "cell_type": "markdown",
      "source": [
        " \u00bfEste es un buen modelo? \u00bfC\u00f3mo determinar\u00edas la magnitud de este error?\n",
        "\n",
        "El error cuadr\u00e1tico medio (MSE) puede ser dif\u00edcil de interpretar; es por esto que generalmente observamos el error de la ra\u00edz cuadrada de la media (RMSE) en su lugar. Una propiedad interesante del RMSE es que se puede interpretar en la misma escala que los objetivos originales.\n",
        "\n",
        "Comparemos el RMSE con la diferencia del m\u00edn. y el m\u00e1x. de nuestros objetivos:"
      ]
    },
    {
      "metadata": {
        "id": "7UwqGbbxP53O",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "min_house_value = california_housing_dataframe[\"median_house_value\"].min()\n",
        "max_house_value = california_housing_dataframe[\"median_house_value\"].max()\n",
        "min_max_difference = max_house_value - min_house_value\n",
        "\n",
        "print(\"Min. Median House Value: %0.3f\" % min_house_value)\n",
        "print(\"Max. Median House Value: %0.3f\" % max_house_value)\n",
        "print(\"Difference between Min. and Max.: %0.3f\" % min_max_difference)\n",
        "print(\"Root Mean Squared Error: %0.3f\" % root_mean_squared_error)"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "JigJr0C7Pzit",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " Nuestro error abarca casi la mitad del rango de los valores objetivo. \u00bfPodemos obtener un mejor desempe\u00f1o?\n",
        "\n",
        "Esta es la pregunta que molesta a todo programador de modelos. Desarrollemos algunas estrategias b\u00e1sicas para reducir el error del modelo.\n",
        "\n",
        "Lo primero que podemos hacer es observar qu\u00e9 tan bien coinciden nuestras predicciones con nuestros objetivos, en t\u00e9rminos de estad\u00edsticas generales de resumen."
      ]
    },
    {
      "metadata": {
        "id": "941nclxbzqGH",
        "colab_type": "code",
        "slideshow": {
          "slide_type": "-"
        },
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          },
          "test": {
            "output": "ignore",
            "timeout": 600
          }
        },
        "cellView": "both"
      },
      "source": [
        "calibration_data = pd.DataFrame()\n",
        "calibration_data[\"predictions\"] = pd.Series(predictions)\n",
        "calibration_data[\"targets\"] = pd.Series(targets)\n",
        "calibration_data.describe()"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "E2-bf8Hq36y8",
        "colab_type": "text",
        "slideshow": {
          "slide_type": "-"
        }
      },
      "cell_type": "markdown",
      "source": [
        " Bien, es posible que esta informaci\u00f3n resulte \u00fatil. \u00bfC\u00f3mo se compara el valor medio con el RMSE del modelo? \u00bfQu\u00e9 ocurre con los diferentes cuantiles?\n",
        "\n",
        "Tambi\u00e9n podemos visualizar los datos y la l\u00ednea que aprendimos. Recuerda que la regresi\u00f3n lineal en un solo atributo puede representarse como una l\u00ednea que asigna la entrada *x* al resultado *y*.\n",
        "\n",
        "Primero, obtendremos una muestra aleatoria uniforme de los datos para poder realizar una representaci\u00f3n de dispersi\u00f3n que se pueda leer."
      ]
    },
    {
      "metadata": {
        "id": "SGRIi3mAU81H",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "sample = california_housing_dataframe.sample(n=300)"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "N-JwuJBKU81J",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " A continuaci\u00f3n, representaremos la l\u00ednea que aprendimos, dibuj\u00e1ndola a partir del t\u00e9rmino de ordenada al origen y la ponderaci\u00f3n del atributo del modelo, junto con la representaci\u00f3n de dispersi\u00f3n. La l\u00ednea se mostrar\u00e1 de color rojo."
      ]
    },
    {
      "metadata": {
        "id": "7G12E76-339G",
        "colab_type": "code",
        "slideshow": {
          "slide_type": "-"
        },
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          },
          "test": {
            "output": "ignore",
            "timeout": 600
          }
        },
        "cellView": "both"
      },
      "source": [
        "# Get the min and max total_rooms values.\n",
        "x_0 = sample[\"total_rooms\"].min()\n",
        "x_1 = sample[\"total_rooms\"].max()\n",
        "\n",
        "# Retrieve the final weight and bias generated during training.\n",
        "weight = linear_regressor.get_variable_value('linear/linear_model/total_rooms/weights')[0]\n",
        "bias = linear_regressor.get_variable_value('linear/linear_model/bias_weights')\n",
        "\n",
        "# Get the predicted median_house_values for the min and max total_rooms values.\n",
        "y_0 = weight * x_0 + bias \n",
        "y_1 = weight * x_1 + bias\n",
        "\n",
        "# Plot our regression line from (x_0, y_0) to (x_1, y_1).\n",
        "plt.plot([x_0, x_1], [y_0, y_1], c='r')\n",
        "\n",
        "# Label the graph axes.\n",
        "plt.ylabel(\"median_house_value\")\n",
        "plt.xlabel(\"total_rooms\")\n",
        "\n",
        "# Plot a scatter plot from our data sample.\n",
        "plt.scatter(sample[\"total_rooms\"], sample[\"median_house_value\"])\n",
        "\n",
        "# Display graph.\n",
        "plt.show()"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "t0lRt4USU81L",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " Esta l\u00ednea inicial se ve muy alejada. F\u00edjate si puedes observar las estad\u00edsticas de resumen y ver la misma informaci\u00f3n codificada all\u00ed.\n",
        "\n",
        "En conjunto, estos controles de estado sugieren que posiblemente podamos encontrar una l\u00ednea mucho m\u00e1s satisfactoria."
      ]
    },
    {
      "metadata": {
        "id": "AZWF67uv0HTG",
        "colab_type": "text",
        "slideshow": {
          "slide_type": "slide"
        }
      },
      "cell_type": "markdown",
      "source": [
        " ## Ajuste de los hiperpar\u00e1metros del modelo\n",
        "Para este ejercicio, colocamos todo el c\u00f3digo anterior en una sola funci\u00f3n por cuestiones pr\u00e1cticas. Puedes llamar a la funci\u00f3n con diferentes par\u00e1metros para ver el efecto.\n",
        "\n",
        "En esta funci\u00f3n, procederemos en 10 per\u00edodos divididos uniformemente para poder observar la mejora del modelo en cada per\u00edodo.\n",
        "\n",
        "Para cada per\u00edodo, computaremos y graficaremos la p\u00e9rdida de entrenamiento. Esto puede ayudarte a determinar cu\u00e1ndo converge un modelo o si este necesita m\u00e1s iteraciones.\n",
        "\n",
        "Tambi\u00e9n representaremos los valores de ponderaci\u00f3n de atributos y t\u00e9rmino de ordenada al origen aprendidos por el modelo en el tiempo. Esta es otra forma de ver c\u00f3mo convergen los elementos."
      ]
    },
    {
      "metadata": {
        "id": "wgSMeD5UU81N",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "def train_model(learning_rate, steps, batch_size, input_feature=\"total_rooms\"):\n",
        "  \"\"\"Trains a linear regression model of one feature.\n",
        "  \n",
        "  Args:\n",
        "    learning_rate: A `float`, the learning rate.\n",
        "    steps: A non-zero `int`, the total number of training steps. A training step\n",
        "      consists of a forward and backward pass using a single batch.\n",
        "    batch_size: A non-zero `int`, the batch size.\n",
        "    input_feature: A `string` specifying a column from `california_housing_dataframe`\n",
        "      to use as input feature.\n",
        "  \"\"\"\n",
        "  \n",
        "  periods = 10\n",
        "  steps_per_period = steps / periods\n",
        "\n",
        "  my_feature = input_feature\n",
        "  my_feature_data = california_housing_dataframe[[my_feature]]\n",
        "  my_label = \"median_house_value\"\n",
        "  targets = california_housing_dataframe[my_label]\n",
        "\n",
        "  # Create feature columns.\n",
        "  feature_columns = [tf.feature_column.numeric_column(my_feature)]\n",
        "  \n",
        "  # Create input functions.\n",
        "  training_input_fn = lambda:my_input_fn(my_feature_data, targets, batch_size=batch_size)\n",
        "  prediction_input_fn = lambda: my_input_fn(my_feature_data, targets, num_epochs=1, shuffle=False)\n",
        "  \n",
        "  # Create a linear regressor object.\n",
        "  my_optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)\n",
        "  my_optimizer = tf.contrib.estimator.clip_gradients_by_norm(my_optimizer, 5.0)\n",
        "  linear_regressor = tf.estimator.LinearRegressor(\n",
        "      feature_columns=feature_columns,\n",
        "      optimizer=my_optimizer\n",
        "  )\n",
        "\n",
        "  # Set up to plot the state of our model's line each period.\n",
        "  plt.figure(figsize=(15, 6))\n",
        "  plt.subplot(1, 2, 1)\n",
        "  plt.title(\"Learned Line by Period\")\n",
        "  plt.ylabel(my_label)\n",
        "  plt.xlabel(my_feature)\n",
        "  sample = california_housing_dataframe.sample(n=300)\n",
        "  plt.scatter(sample[my_feature], sample[my_label])\n",
        "  colors = [cm.coolwarm(x) for x in np.linspace(-1, 1, periods)]\n",
        "\n",
        "  # Train the model, but do so inside a loop so that we can periodically assess\n",
        "  # loss metrics.\n",
        "  print(\"Training model...\")\n",
        "  print(\"RMSE (on training data):\")\n",
        "  root_mean_squared_errors = []\n",
        "  for period in range (0, periods):\n",
        "    # Train the model, starting from the prior state.\n",
        "    linear_regressor.train(\n",
        "        input_fn=training_input_fn,\n",
        "        steps=steps_per_period\n",
        "    )\n",
        "    # Take a break and compute predictions.\n",
        "    predictions = linear_regressor.predict(input_fn=prediction_input_fn)\n",
        "    predictions = np.array([item['predictions'][0] for item in predictions])\n",
        "    \n",
        "    # Compute loss.\n",
        "    root_mean_squared_error = math.sqrt(\n",
        "        metrics.mean_squared_error(predictions, targets))\n",
        "    # Occasionally print the current loss.\n",
        "    print(\"  period %02d : %0.2f\" % (period, root_mean_squared_error))\n",
        "    # Add the loss metrics from this period to our list.\n",
        "    root_mean_squared_errors.append(root_mean_squared_error)\n",
        "    # Finally, track the weights and biases over time.\n",
        "    # Apply some math to ensure that the data and line are plotted neatly.\n",
        "    y_extents = np.array([0, sample[my_label].max()])\n",
        "    \n",
        "    weight = linear_regressor.get_variable_value('linear/linear_model/%s/weights' % input_feature)[0]\n",
        "    bias = linear_regressor.get_variable_value('linear/linear_model/bias_weights')\n",
        "\n",
        "    x_extents = (y_extents - bias) / weight\n",
        "    x_extents = np.maximum(np.minimum(x_extents,\n",
        "                                      sample[my_feature].max()),\n",
        "                           sample[my_feature].min())\n",
        "    y_extents = weight * x_extents + bias\n",
        "    plt.plot(x_extents, y_extents, color=colors[period]) \n",
        "  print(\"Model training finished.\")\n",
        "\n",
        "  # Output a graph of loss metrics over periods.\n",
        "  plt.subplot(1, 2, 2)\n",
        "  plt.ylabel('RMSE')\n",
        "  plt.xlabel('Periods')\n",
        "  plt.title(\"Root Mean Squared Error vs. Periods\")\n",
        "  plt.tight_layout()\n",
        "  plt.plot(root_mean_squared_errors)\n",
        "\n",
        "  # Output a table with calibration data.\n",
        "  calibration_data = pd.DataFrame()\n",
        "  calibration_data[\"predictions\"] = pd.Series(predictions)\n",
        "  calibration_data[\"targets\"] = pd.Series(targets)\n",
        "  display.display(calibration_data.describe())\n",
        "\n",
        "  print(\"Final RMSE (on training data): %0.2f\" % root_mean_squared_error)"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "kg8A4ArBU81Q",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " ## Tarea\u00a01: Logra un RMSE de 180 o m\u00e1s bajo\n",
        "\n",
        "Ajusta los hiperpar\u00e1metros del modelo para mejorar la p\u00e9rdida y adaptar mejor la distribuci\u00f3n objetivo.\n",
        "Si despu\u00e9s de aproximadamente 5\u00a0minutos tienes problemas para obtener un RMSE de 180 o m\u00e1s bajo, comprueba la soluci\u00f3n para conocer una combinaci\u00f3n posible."
      ]
    },
    {
      "metadata": {
        "id": "UzoZUSdLIolF",
        "colab_type": "code",
        "slideshow": {
          "slide_type": "slide"
        },
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          },
          "test": {
            "output": "ignore",
            "timeout": 600
          }
        },
        "cellView": "both"
      },
      "source": [
        "train_model(\n",
        "    learning_rate=0.00001,\n",
        "    steps=100,\n",
        "    batch_size=1\n",
        ")"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "ajVM7rkoYXeL",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " ### Soluci\u00f3n\n",
        "\n",
        "Haz clic m\u00e1s abajo para conocer una soluci\u00f3n posible."
      ]
    },
    {
      "metadata": {
        "id": "T3zmldDwYy5c",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "train_model(\n",
        "    learning_rate=0.00002,\n",
        "    steps=500,\n",
        "    batch_size=5\n",
        ")"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "M8H0_D4vYa49",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " Esta es solo una configuraci\u00f3n posible; es posible que existan otras combinaciones de configuraciones que tambi\u00e9n den buenos resultados. Ten en cuenta que, en general, este ejercicio no se trata de buscar la *mejor* configuraci\u00f3n, sino de ayudarte a desarrollar tu intuici\u00f3n sobre c\u00f3mo el ajuste de la configuraci\u00f3n del modelo afecta la calidad de la predicci\u00f3n."
      ]
    },
    {
      "metadata": {
        "id": "QU5sLyYTqzqL",
        "colab_type": "text",
        "slideshow": {
          "slide_type": "slide"
        }
      },
      "cell_type": "markdown",
      "source": [
        " ### \u00bfHay una heur\u00edstica est\u00e1ndar para el ajuste del modelo?\n",
        "\n",
        "Esta es una pregunta frecuente. La respuesta breve es que los efectos de los diferentes hiperpar\u00e1metros dependen de los datos. Por lo tanto, no hay reglas estrictas; debes probarlos en tus datos.\n",
        "\n",
        "Dicho esto, aqu\u00ed se incluyen algunas reglas generales que pueden ayudarte como gu\u00eda:\n",
        "\n",
        " * El error de entrenamiento debe disminuir constantemente, de manera abrupta al principio y eventualmente estancarse a medida que converge el entrenamiento.\n",
        " * Si el entrenamiento no convirgi\u00f3, prueba ejecutarlo durante m\u00e1s tiempo.\n",
        " * Si el error de entrenamiento disminuye muy lentamente, aumentar la tasa de entrenamiento puede ayudar a que disminuya m\u00e1s r\u00e1pido.\n",
        "   * Sin embargo, en algunas ocasiones puede ocurrir exactamente lo opuesto si la tasa de aprendizaje es demasiado alta.\n",
        " * Si el error de entrenamiento var\u00eda extremadamente, prueba disminuir la tasa de aprendizaje.\n",
        "   * Una tasa de aprendizaje m\u00e1s baja con un n\u00famero m\u00e1s alto de pasos o un tama\u00f1o del lote m\u00e1s grande suelen ser una buena combinaci\u00f3n.\n",
        " * Los tama\u00f1os del lote muy peque\u00f1os tambi\u00e9n pueden causar inestabilidad. Primero prueba valores m\u00e1s altos, como 100 o 1,000, y dismin\u00fayelos hasta que observes degradaci\u00f3n.\n",
        "\n",
        "Como dijimos antes, nunca te rijas estrictamente por estas reglas generales, porque los efectos dependen de los datos. Siempre debes experimentar y verificar."
      ]
    },
    {
      "metadata": {
        "id": "GpV-uF_cBCBU",
        "colab_type": "text",
        "slideshow": {
          "slide_type": "slide"
        }
      },
      "cell_type": "markdown",
      "source": [
        " ## Tarea\u00a02: Prueba un atributo diferente\n",
        "\n",
        "Observa si puedes obtener un mejor desempe\u00f1o al reemplazar el atributo `total_rooms` por el atributo `population`.\n",
        "\n",
        "No dediques m\u00e1s de 5\u00a0minutos a esta actividad."
      ]
    },
    {
      "metadata": {
        "id": "YMyOxzb0ZlAH",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "# YOUR CODE HERE"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "ci1ISxxrZ7v0",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " ### Soluci\u00f3n\n",
        "\n",
        "Haz clic m\u00e1s abajo para conocer una soluci\u00f3n posible."
      ]
    },
    {
      "metadata": {
        "id": "SjdQQCduZ7BV",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "train_model(\n",
        "    learning_rate=0.00002,\n",
        "    steps=1000,\n",
        "    batch_size=5,\n",
        "    input_feature=\"population\"\n",
        ")"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    }
  ]
}
